﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using OMLWP = DocumentFormat.OpenXml.Wordprocessing;

using NUnit.Framework ;
using DocumentModelFake;

namespace OpenXmlDemo
{

    [TestFixture]
    class OpenXmlDemoIntegrationTest
    {

        #region TestHelpers

        public static Paragraph GenerateParagraph(string paragraphText)
        {
            var element =
                new Paragraph(
                    new Run(
                        new OMLWP.Text(paragraphText))
                );
            //-Return 
            return element;

        }

        public string GetElfDocTestPath()
        {
            //-Code

            string appBase = AppDomain.CurrentDomain.BaseDirectory;
            string appBaseRoot = appBase.Replace("\\bin", "");
            appBaseRoot = appBaseRoot.Replace("\\Debug", "");

            string testDocPath = Path.Combine(appBaseRoot, @"DocumentTemplate\ElfDocTest\OpenXmlDemo");

            //-Return
            return testDocPath;
        
        }

        public string GetTargetOUtFileName(string templateSourceFilePathName )
        {
            //-Code
            string fileName = "Out_" + templateSourceFilePathName + "_" + String.Format("{0:yyyyMMdd-HHmmss}", DateTime.Now) ;
            //-Return
            return fileName  ;
        }

        public DocumentModel GetBasicStandardElfDocTestDocumentModel()
        {
            //-Code
            var model = new DocumentModel();
            //-Return
            return model; 
        }
        #endregion 

        [Test]
        public void OpenXmlDemo_should_create_docx_with_hello_world()
        {

            //-Arrange

            //-Act

            var file = Path.Combine(GetElfDocTestPath(), @"Out_OpenXmlDemo_HellowWorldDocument.docx");
            
            using( WordprocessingDocument package = WordprocessingDocument.Create(file , WordprocessingDocumentType.Document ))
            {
                // add main document part to as yet empty package( openxmldoc )
                var filePackageMainDocumentPart = package.AddMainDocumentPart();
                
                // create in memory body ...
                var body =  new Body
                (
                    GenerateParagraph("Hellow World b")
                    , GenerateParagraph("Hellow World 2")
                    , GenerateParagraph("Hellow World 3" )
                );

                // add body to in memory document
                var document = new Document( body ) ;

                // save document dom into main document part
                document.Save(filePackageMainDocumentPart); 

            }

            //-Assert

        }

        [Test]
        public void OpenXmlDemo_template_create_document_replace_content_control_with_external_document_with_altChunk_method_should_create_out_file()
        {

            //-Arrange

            //-Act

            // get some source and target document names
            string source = @"OpenXmlDemo_FileMergeWithContentControl.docx"; 
            string target = "Out_" + source ; 

            
            var sourceFilePathname = Path.Combine( GetElfDocTestPath() , source ) ;
            var targetFilePathname = Path.Combine(GetElfDocTestPath(), target);
            
            // copy the source with it's content controls a target file . The target file will other stuff poked to it
            File.Copy( sourceFilePathname , targetFilePathname, true  ) ;

            // the content control has "Earth" as its title-alias, get a file that is implied by that alias name
            string sourceKey = "Earth";
            string sourceFile = Path.Combine(GetElfDocTestPath(), "OpenXmlDemo_FileMergeWithContentControl_Earth.docx"); 

            //
            using (var discDocument= WordprocessingDocument.Open(targetFilePathname , true ))
            {

                // get main document part of the disc file
                var mainDocumentPart  = discDocument.MainDocumentPart;

                // cc list that have the document name in the alias title
                var contentControlList = mainDocumentPart
                                        .Document
                                        .Descendants<SdtBlock>()
                                        .Where(s => sourceKey.Contains(s.SdtProperties.GetFirstChild<SdtAlias>().Val.Value)).ToList();

                // used to count over content controls that are pointing to the document that should be merged into the target document
                int id = 0 ; 

                // if there content controls that are asking for that external sourced constituent document
                if ( contentControlList.Count != 0 )
                {

                    // for each content control that is asking for a constituent document
                    foreach ( var contentControl in contentControlList)
                    {

                        // make up id for the chunk
                        var chunkNew = new AltChunk { Id = "altChunkID" + id };

                        // Ad chunk to main document part, 
                        // ... and give it the id we have chosen 
                        // ... get a handle to the new chunk ...
                        // ... stuff some data into the new chunk from a disc file, ... an office disc file ...
                        var chunkDiscData = mainDocumentPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, chunkNew.Id);
                        chunkDiscData.FeedData( File.Open(sourceFile, FileMode.Open) ); 

                        // get the parent element of the content control
                        var contentControlParentElement = contentControl.Parent;

                        // insert the element after the contentControl ...
                        contentControlParentElement.InsertAfter(chunkNew, contentControl);

                        // remove the particular content control we are poking data at.
                        contentControl.Remove();

                        // increment the id
                        id++;

                    }

                }

            }

            //-Assert

        }

        [Test]
        public void OpenXmlDemo_template_create_document_replace_content_control_with_plain_text_with_altChunk_method_should_create_out_file()
        {

            //-Arrange

            //-Act

            // get some source and target document names
            string source = @"OpenXmlDemo_PlainTextMergeWithContentControl.docx";
            string target = "Out_" + source;


            var sourceFilePathname = Path.Combine(GetElfDocTestPath(), source);
            var targetFilePathname = Path.Combine(GetElfDocTestPath(), target);

            // copy the source with it's content controls a target file . The target file will other stuff poked to it
            File.Copy(sourceFilePathname, targetFilePathname, true);

            // the content control has "Earth" as its title-alias, get a file that is implied by that alias name
            string sourceKey = "Earth";

            //
            using (var discDocument = WordprocessingDocument.Open(targetFilePathname, true))
            {

                // get main document part of the disc file
                var mainDocumentPart = discDocument.MainDocumentPart;

                // get content control list that have required key in the alias title
                var contentControlList = mainDocumentPart
                                        .Document
                                        .Descendants<SdtBlock>()
                                        .Where( s => 
                                            sourceKey.Contains(s.SdtProperties.GetFirstChild<SdtAlias>().Val.Value)
                                        )
                                        .ToList();

                // used to count over content controls that are pointing to the document that should be merged into the target document
                int id = 0;

                // if there content controls that are asking for that external sourced constituent document
                if ( contentControlList.Count != 0 )
                {

                    // for each content control that is asking for a constituent document
                    foreach( var contentControl in contentControlList)
                    {

                        // make up id for the chunk
                        var chunkNew = new AltChunk { Id = "altChunkID" + id };
                        MemoryStream plainTextMemoryStream = new MemoryStream(ASCIIEncoding.Default.GetBytes("the quick brown fox jumped over the lazy dog. "));

                        // Add chunk to main document part, 
                        // ... and give it the id we have chosen 
                        // ... stuff some data into the new chunk from a disc file, ... 
                        // ... get returned handle to the chunk added ...
                        var chunkData = mainDocumentPart.AddAlternativeFormatImportPart( AlternativeFormatImportPartType.TextPlain , chunkNew.Id );

                        // ... stuff some plain text ...
                        chunkData.FeedData( plainTextMemoryStream ) ;

                        // get the parent element of the content control
                        var contentControlParentElement = contentControl.Parent;

                        // insert the element after the contentControl ...
                        contentControlParentElement.InsertAfter(chunkNew, contentControl);

                        // remove the particular content control we were poking data at.
                        contentControl.Remove();

                        // increment the id
                        id++;

                    }

                }

            }

            //-Assert

        }

        [Test]
        public void OpenXmlDemo_read_all_text_in_a_docx_file_should_include_the_quick_brown_fox()
        {

            //-Arrange

            //-Act

            // get some source and target document names
            string source = @"OpenXmlDemo_IncludesTheQuickBrownFoxText.docx";
            string target = "Out_" + source;

            var sourceFilePathname = Path.Combine(GetElfDocTestPath(), source);
            var targetFilePathname = Path.Combine(GetElfDocTestPath(), target);

            // copy the source with it's content controls a target file . The target file will other stuff poked to it
            File.Copy(sourceFilePathname, targetFilePathname, true);

            //
            string docText = string.Empty ; 

            // open the file, and read the text nodes
            using (var discDocument = WordprocessingDocument.Open(targetFilePathname, true))
            {

                // get main document part of the disc file
                var mainDocumentPart = discDocument.MainDocumentPart;

                // get content control list that have required key in the alias title
                var elementList = mainDocumentPart
                                        .Document
                                        .Descendants<OMLWP.Text>()
                                        .ToList();



                // if there content controls that are asking for that external sourced constituent document
                if (elementList.Count != 0)
                {

                    // for each content control that is asking for a constituent document
                    foreach (var element  in elementList)
                    {
                        docText += element.Text; 
                    }

                }

            }

            //-Assert
            Assert.That(docText.Contains("The quick brown fox"));

        }

        [Test]
        public void OpenXmlDemo_apply_style_to_paragraph_should_include_the_quick_brown_fox()
        {

            //-Arrange

            //-Act

            // get some source and target document names
            string source = @"OpenXmlDemo_ApplyStyleToParagraph.docx";
            string target = "Out_" + source;

            var sourceFilePathname = Path.Combine(GetElfDocTestPath(), source);
            var targetFilePathname = Path.Combine(GetElfDocTestPath(), target);

            // copy the source with it's content controls a target file . The target file will other stuff poked to it
            File.Copy(sourceFilePathname, targetFilePathname, true);

            //
            using (WordprocessingDocument doc = WordprocessingDocument.Open(targetFilePathname, true))
            {

                // Get the first paragraph.
                Paragraph p = doc.MainDocumentPart.Document.Body.Elements<Paragraph>().First();

                // If the paragraph has no ParagraphProperties objects, create a new one for it.
                if (p.Elements<ParagraphProperties>().Count() == 0)
                {
                    p.PrependChild<ParagraphProperties>(new ParagraphProperties());
                }

                // Get the paragraph properties element of the paragraph.
                ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();

                // Set the paragraph style ID to "Heading1".
                pPr.ParagraphStyleId = new ParagraphStyleId() { Val = "Heading1" };

            }

            //-Assert
            //Assert.That( ... paragraph has style ...);

        }

    }

}
